﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.ServiceModel.DomainServices.Client;
using System.Threading;
using System.Windows.Controls;
using System.Windows.Markup;
using NetBay.Core.BusinessEntities;
using Rio.Applications.Web.Services;
using Rio.Framework.Localisation;
using Rio.Framework.Pages.AppCode.Helpers.Utils;
using Rio.Framework.Pages.Context;

namespace Rio.Framework.Pages.ChildWindows
{
    public partial class ChangePasswordChildWindows : INotifyDataErrorInfo, INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;
        public event EventHandler<DataErrorsChangedEventArgs> ErrorsChanged;

        private Dictionary<string, List<string>> errors = new Dictionary<string, List<string>>();
        private string _newPasswordConfirm = String.Empty;
        private string _oldPassword = String.Empty;
        private string _newPassword = String.Empty;

        public string ValidationSummaryHeaderLabel { get; set; }

        public bool HasErrors
        {
            get { return this.errors.Count > 0; }
        }

        public string OldPassword
        {
            get { return _oldPassword; }
            set
            {
                _oldPassword = value;
                OnPropertyChanged("OldPassword");
            }
        }

        public string NewPassword
        {
            get { return _newPassword; }
            set
            {
                _newPassword = value;

                OnPropertyChanged("NewPassword");
            }
        }

        public string NewPasswordConfirm
        {
            get { return _newPasswordConfirm; }
            set
            {
                _newPasswordConfirm = value;

                OnPropertyChanged("NewPasswordConfirm");
            }
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="ChangePasswordChildWindows"/> class.
        /// </summary>
        public ChangePasswordChildWindows()
        {
            InitializeComponent();

            Language = XmlLanguage.GetLanguage(Thread.CurrentThread.CurrentCulture.TwoLetterISOLanguageName);

            InitLabels();
        }

        /// <summary>
        /// Inits the labels.
        /// </summary>
        private void InitLabels()
        {
            Header = Resx.GetLabel(ResxOfficePage.ChangePassword_Title);
            NewPasswordTextBlock.Text = Resx.GetLabel(ResxOfficePage.ChangePassword_NewPassword);
            NewPasswordConfirmTextBlock.Text = Resx.GetLabel(ResxOfficePage.ChangePassword_NewPasswordConfirm);
            ActualPasswordTextBlock.Text = Resx.GetLabel(ResxOfficePage.ChangePassword_ActualPassword);
            NoteTextBlock.Text = Resx.GetLabel(ResxOfficePage.ChangePassword_Note);
            ValidateButton.Content = Resx.GetLabel(ResxOfficePage.ChangePassword_Validate);
            CancelButton.Content = Resx.GetLabel(ResxOfficePage.ChangePassword_Cancel);

            ValidationSummaryHeaderLabel = Resx.GetLabel(ResxOfficePage.ChangePassword_Errors);
        }

        /// <summary>
        /// Validates the password.
        /// </summary>
        /// <returns></returns>
        private bool ValidatePassword()
        {
            bool isValid = false;

            string oldEncryptedPassword = MD5Core.GetHashString(OldPassword).ToLowerInvariant();

            if (oldEncryptedPassword != GlobalWebContext.CurrentUser.Password)
            {
                AddError("OldPassword", Resx.GetLabel(ResxOfficePage.ChangePassword_Error01));
            }
            else
            {
                RemoveError("OldPassword", Resx.GetLabel(ResxOfficePage.ChangePassword_Error01));

                if (String.IsNullOrWhiteSpace(_newPassword))
                {
                    AddError("NewPassword", Resx.GetLabel(ResxOfficePage.ChangePassword_Error02));
                }
                else
                {
                    RemoveError("NewPassword", Resx.GetLabel(ResxOfficePage.ChangePassword_Error02));

                    if (_newPassword != _newPasswordConfirm)
                    {
                        AddError("NewPasswordConfirm", Resx.GetLabel(ResxOfficePage.ChangePassword_Error03));
                    }
                    else
                    {
                        RemoveError("NewPasswordConfirm", Resx.GetLabel(ResxOfficePage.ChangePassword_Error03));

                        isValid = true;
                    }
                }
            }

            OnDataErrorsChanged("OldPassword");
            OnDataErrorsChanged("NewPassword");
            OnDataErrorsChanged("NewPasswordConfirm");

            return isValid;
        }

        /// <summary>
        /// Handles the Click event of the CancelButton control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.Windows.RoutedEventArgs"/> instance containing the event data.</param>
        private void CancelButton_Click(object sender, System.Windows.RoutedEventArgs e)
        {
            DialogResult = false;

            Close();
        }

        /// <summary>
        /// Handles the Click event of the ValidateButton control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.Windows.RoutedEventArgs"/> instance containing the event data.</param>
        private void ValidateButton_Click(object sender, System.Windows.RoutedEventArgs e)
        {
            ValidationSummary.Errors.Clear();

            if (ValidatePassword())
            {
                BusyIndicator.Visibility = System.Windows.Visibility.Visible;

                string encryptedPassword = MD5Core.GetHashString(OldPassword).ToLowerInvariant();
                string encryptedNewPassword = MD5Core.GetHashString(NewPassword).ToLowerInvariant();

                BusinessEntitiesDomainContext businessEntitiesDomainContext = new BusinessEntitiesDomainContext();
                businessEntitiesDomainContext.UpdateUserPassword(
                    GlobalWebContext.CurrentUser.UserId,
                    encryptedPassword,
                    encryptedNewPassword,
                    UpdatePasswordCallback,
                    null);
            }
        }

        /// <summary>
        /// Updates the password callback.
        /// </summary>
        /// <param name="result">The result.</param>
        private void UpdatePasswordCallback(InvokeOperation<ReturnBoolean> result)
        {
            BusyIndicator.Visibility = System.Windows.Visibility.Collapsed;

            if (result.Value.Value)
            {
                DialogResult = true;
                Close();
            }
            else
            {
                ValidationSummary.Errors.Add(new ValidationSummaryItem(Resx.GetLabel(ResxOfficePage.ChangePassword_Error04)));

                DialogResult = false;
            }
        }

        /// <summary>
        /// Called when [property changed].
        /// </summary>
        /// <param name="propertyName">Name of the property.</param>
        private void OnPropertyChanged(string propertyName)
        {
            if (this.PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }

        #region Errors Management

        /// <summary>
        /// Gets the validation errors for a specified property or for the entire object.
        /// </summary>
        /// <param name="propertyName">The name of the property to retrieve validation errors for, or null or <see cref="F:System.String.Empty"/> to retrieve errors for the entire object.</param>
        /// <returns>
        /// The validation errors for the property or object.
        /// </returns>
        public IEnumerable GetErrors(string propertyName)
        {
            if (string.IsNullOrEmpty(propertyName) || !this.errors.ContainsKey(propertyName))
            {
                return null;
            }

            return this.errors[propertyName];
        }

        /// <summary>
        /// Adds the error.
        /// </summary>
        /// <param name="propertyName">Name of the property.</param>
        /// <param name="errorMessage">The error message.</param>
        protected virtual void AddError(string propertyName, string errorMessage)
        {
            if (!this.errors.ContainsKey(propertyName))
            {
                this.errors.Add(propertyName, new List<String>());
            }

            if (!this.errors[propertyName].Contains(errorMessage))
            {
                this.errors[propertyName].Add(errorMessage);
                this.OnDataErrorsChanged(propertyName);
            }
        }

        /// <summary>
        /// Removes the error.
        /// </summary>
        /// <param name="propertyName">Name of the property.</param>
        /// <param name="errorMessage">The error message.</param>
        protected virtual void RemoveError(string propertyName, string errorMessage)
        {
            if (this.errors.ContainsKey(propertyName))
            {
                if (this.errors[propertyName].Contains(errorMessage))
                {
                    this.errors[propertyName].Remove(errorMessage);
                    if (this.errors[propertyName].Count == 0)
                    {
                        this.errors.Remove(propertyName);
                    }

                    this.OnDataErrorsChanged(propertyName);
                }
            }
        }

        /// <summary>
        /// Called when [data errors changed].
        /// </summary>
        /// <param name="propertyName">Name of the property.</param>
        private void OnDataErrorsChanged(string propertyName)
        {
            if (this.ErrorsChanged != null)
            {
                this.ErrorsChanged(this, new DataErrorsChangedEventArgs(propertyName));
            }
        }

        #endregion
    }
}
